﻿using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.Win32;
using Communication;
using _698._45Tool.Utils;
using GalaSoft.MvvmLight.Messaging;
using nblTool.utils;
using System.Threading;
using DocumentFormat.OpenXml.ExtendedProperties;
using System.Net;
using CommonServiceLocator;
using Jn698._45GWTool.Communication;

namespace Jn698._45GWTool.ViewModels.Controls
{
    public class RemoteUpgradeViewModel:ViewModelBase
    {
        private SerialPortHelper serialPortHelper = SerialPortHelper.Instance;
        private TcpHelper tcpHelper = TcpHelper.Instance;
        private static byte[] fileBytes;
        private static CancellationTokenSource cts;
        private static Task MainTask = null;
        private static int file_i=0;
        public RemoteUpgradeViewModel()
        {
            APDULen = 1024;
            FileTypeList = new List<string>() { "终端文件","本地通信模块文件","远程通信模块文件","采集器文件","从节点通信文件"};
            FileTypeIndex = 0;
            BtnName = "停止发送";
        }

        private bool? commState;

        public bool? CommState
        {
            get
            {
                if (commState == null)
                {
                    commState = true;
                }
                return commState;
            }
            set { commState = value; RaisePropertyChanged(); }
        }
        private string btnName;

        public string BtnName
        {
            get { return btnName; }
            set { btnName = value; RaisePropertyChanged(); }
        }

        private string progress;

        public string Progress
        {
            get { return progress; }
            set { progress = value; RaisePropertyChanged(); }
        }

        private string filePath;

		public string FilePath
		{
			get { return filePath; }
			set { filePath = value; RaisePropertyChanged(); }
		}

		private int apduLen;

		public int APDULen
		{
			get { return apduLen; }
			set { apduLen = value;RaisePropertyChanged(); }
		}

		private int fileTypeIndex;

		public int FileTypeIndex
		{
			get { return fileTypeIndex; }
			set { fileTypeIndex = value; RaisePropertyChanged(); }
		}

        private List<string> fileTypeList;

        public List<string> FileTypeList
        {
            get { return fileTypeList; }
            set { fileTypeList = value; }
        }

        private async Task awitTCPRecv(int timeOutSec,CancellationToken ctsToken)
        {
            using (var tokenSource = new CancellationTokenSource())
            {

                var startTime = DateTime.Now;
                while (true)
                {
                    try
                    {
                        if (ctsToken.IsCancellationRequested)
                        {
                            return;
                        }
                        if ((DateTime.Now - startTime) >= TimeSpan.FromSeconds(timeOutSec))
                        {
                            tokenSource.Cancel();
                        }
                        if (tokenSource.IsCancellationRequested)
                        {
                            return;
                        }
                        if (tcpHelper.isComplete == true)
                        {
                            return;
                        }
                        await Task.Delay(TimeSpan.FromMilliseconds(1000), ctsToken);
                    }
                    catch (OperationCanceledException)
                    {
                        Console.WriteLine("任务暂停");
                        
                    }
                }
            }
        }
        private string GetStartFrame(byte[] bytes)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append("020302060A000A0006");
			sb.Append(bytes.Length.ToString("X8"));
			sb.Append("0408E00A043030303016");
			sb.Append(FileTypeIndex.ToString("X2"));
			sb.Append("12");
            sb.Append(APDULen.ToString("X4"));
            sb.Append("020216000900");
            return sb.ToString();
        }
        private string GetUpgdeFrame(int index,byte[] bytes)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("020212");
            sb.Append(index.ToString("X4"));
            sb.Append("09");
            if (bytes.Length<=0xff)
            {
                sb.Append(bytes.Length.ToString("X2"));
            }
            else
            {
                sb.Append("82");
                sb.Append(bytes.Length.ToString("X4"));
            }
            
            sb.Append(string.Join("", bytes.Select(x=>x.ToString("X2"))));
            return sb.ToString();
        }

        public async Task<bool> StartTask(string address, byte[] bytes,int SecuritySelected,CancellationTokenSource cts)
		{
			bool result_flag = false;
            Dictionary<string, string> map = new Dictionary<string, string>
            {
                { "F0010700", GetStartFrame(bytes) }
            };
            var b= MessageGenerationModule.MessageGeneration(address,MessageGenerationModule.ActionMode.ActionRequest, map, SecuritySelected);
            Messenger.Default.Send<string>($"发送帧({DateTime.Now.ToString()})：{string.Join(" ", b.Select(x => x.ToString("X2")))}", "SendMessage");
            switch (CommViewModel.selectedCommType)
            {
                case "串口":
                    serialPortHelper.SendDataMethod(b);
                    await Task.Run(() => result_flag=serialPortHelper.DataReceiveFunction());
                    break;
                case "GPRS":
                    tcpHelper.isComplete = false;
                    tcpHelper.SendData(MainViewModel.selectedDevice.DeviceAddress, b);
                    await awitTCPRecv(5, cts.Token);
                    result_flag = tcpHelper.isComplete;
                    break;
                default:
                    break;
            }
            return result_flag;
		}
		public async Task<bool> UpgradeTaskAsync(string address ,byte[] fileBytes,int SecuritySelected, CancellationTokenSource cts)
		{
            bool result_flag = false;
            MainTask =Task.Run(async() =>
            {
                
                int num = fileBytes.Length / 1024;
                if (fileBytes.Length % 1024 > 0)
                {
                    num += 1;
                }

                for (; file_i < num; file_i++)
                {
                    try
                    {
                        if (cts.Token.IsCancellationRequested)
                        {
                            break;
                        }
                        Progress = string.Format("{0}/{1}",file_i+1,num);
                        var data = fileBytes.Length > 1024 ? fileBytes.Take(1024).ToArray() : fileBytes;

                        //发送
                        result_flag = false;

                        Dictionary<string, string> map = new Dictionary<string, string>
                        {
                            { "F0010800", GetUpgdeFrame(file_i,data) }
                        };
                        var b = MessageGenerationModule.MessageGeneration(address, MessageGenerationModule.ActionMode.ActionRequest, map, SecuritySelected);
                        Messenger.Default.Send<string>($"发送帧({DateTime.Now.ToString()})：{string.Join(" ", b.Select(x => x.ToString("X2")))}", "SendMessage");
                        switch (CommViewModel.selectedCommType)
                        {
                            case "串口":
                                serialPortHelper.SendDataMethod(b);
                                await Task.Run(() => result_flag = serialPortHelper.DataReceiveFunction(), cts.Token);
                                break;
                            case "GPRS":
                                tcpHelper.isComplete = false;
                                tcpHelper.SendData(MainViewModel.selectedDevice.DeviceAddress, b);
                                await awitTCPRecv(5,new CancellationTokenSource().Token);
                                result_flag = tcpHelper.isComplete;
                                break;
                            default:
                                break;
                        }
                        if (result_flag == false)
                        {
                            break;
                        }
                        //下发成功
                        if (fileBytes.Length > 1024)
                        {
                            fileBytes = fileBytes.Skip(1024).ToArray();
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        Console.WriteLine("任务暂停");
                    }

                }
                return result_flag;
            }, cts.Token);
            await MainTask;
            return result_flag;

        }


        public RelayCommand LoadPathCommand
		{
			get
			{
				return new RelayCommand(() =>
				{
					try
					{
                        OpenFileDialog openFileDialog = new OpenFileDialog
						{
							/*Filter = "ZIP files (*.zip)|*.zip",
                            Title = "选择ZIP文件",*/
							FileName = "E:\\SVN备份\\国网协议调试工具\\文档\\app(ZB_III).zip"
                        };

                        if (openFileDialog.ShowDialog() == true)
                        {
                            FilePath=openFileDialog.FileName;
                            
                            fileBytes = File.ReadAllBytes(openFileDialog.FileName);
                            Console.WriteLine("文件加载成功，字节数组长度为: " + fileBytes.Length);
                            
							
                        }
                        
                    }
					catch (Exception e)
					{
						MessageBox.Show(e.Message);
					}
                    
                });
			}
		}

        public RelayCommand SendCommand
        {
            get
            {
                return new RelayCommand(async() =>
                {
                    if (MainViewModel.selectedDevice == null)
                    {
                        MessageBox.Show("请选择设备!");
                        return;
                    }
                    if (fileBytes.Length<=0)
                    {
                        MessageBox.Show("文件内容为空!");
                        return;
                    }
                    BtnName = "停止发送";
                    cts = new CancellationTokenSource();
                    CommState = false;
                    SendModule.SecuritySelectedIndex = ServiceLocator.Current.GetInstance<MainViewModel>().SecuritySelectedIndex;
                    switch (SendModule.SecuritySelectedIndex)
                    {

                        //明文+RN_MAC
                        case 2:
                        //明文+SID_MAC
                        case 3:
                        //密文+SID
                        case 4:
                        //密文+SID_MAC
                        case 5:
                            if (string.IsNullOrWhiteSpace(SendModule.SessionInitKey))
                            {
                                MessageBox.Show("请先建立应用连接");
                                return;
                            }
                            break;
                        //明文
                        case 0:
                        //明文+RN
                        case 1:
                        default:

                            break;
                    }
                    if ((await StartTask(MainViewModel.selectedDevice.DeviceAddress, fileBytes, SendModule.SecuritySelectedIndex, cts)) == true)
                    {
                        file_i = 0;
                        await UpgradeTaskAsync(MainViewModel.selectedDevice.DeviceAddress, fileBytes, SendModule.SecuritySelectedIndex, cts);
                        
                    }
                    CommState = true;
                });
            }
        }

        public RelayCommand StopCommand
        {
            get
            {
                return new RelayCommand(async() =>
                {
                    if (BtnName.Equals("停止发送"))
                    {
                        BtnName = "继续发送";
                        cts?.Cancel();
                        Task.WaitAll(MainTask);
                        Messenger.Default.Send<string>($"任务暂停({DateTime.Now.ToString()})\r\n", "StopMessage");

                    }
                    else
                    {
                        BtnName = "停止发送";
                        Messenger.Default.Send<string>($"任务继续({DateTime.Now.ToString()})\r\n", "StopMessage");
                        cts = new CancellationTokenSource();
                        SendModule.SecuritySelectedIndex = ServiceLocator.Current.GetInstance<MainViewModel>().SecuritySelectedIndex;
                        switch (SendModule.SecuritySelectedIndex)
                        {

                            //明文+RN_MAC
                            case 2:
                            //明文+SID_MAC
                            case 3:
                            //密文+SID
                            case 4:
                            //密文+SID_MAC
                            case 5:
                                if (string.IsNullOrWhiteSpace(SendModule.SessionInitKey))
                                {
                                    MessageBox.Show("请先建立应用连接");
                                    return;
                                }
                                break;
                            //明文
                            case 0:
                            //明文+RN
                            case 1:
                            default:

                                break;
                        }
                        await UpgradeTaskAsync(MainViewModel.selectedDevice.DeviceAddress, fileBytes, SendModule.SecuritySelectedIndex, cts);
                    }
                });
            }
        }


	}
}
